package com.baijiayun.liveuibase.toolbox.answerer.barchart;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import com.baijiayun.livecore.utils.LPLogger;
import com.baijiayun.liveuibase.R;
import com.baijiayun.liveuibase.utils.ThemeDataUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 小班课统计的柱状图
 */
public class AnswererBarChart extends View {
    private Paint mBarPaint;
    private Paint mXAxisLabelPaint;
    private Paint mXAxisSelectedLabelPaint;
    private Paint mYAxisValuePaint;
    private Paint mXAxisPaint;
    private Rect mTextRect;
    private Rect mValueRect;
    private Rect mCountRect;
    private Rect mRateRect;
    private RectF mBarRectF;
    private RectF mClipRectF;
    private int mBarWidth;
    private int mGap;
    private int mRadius;
    private boolean canStop;
    private String mCountString = "";
    private String mRateString = "";
    private float mMax = 100;
    private int mStep;
    private float mRatio = 0.7f;
    private float[] mDataList;
    private String[] mHorizontalAxis;
    private List<String> mSelectedAxis;
    private List<AnswererBarEntry> mBars = new ArrayList<>();
    private int[] mColors = {0xFF1795FF, 0xFF1795FF, 0xFF1795FF, 0xFF1795FF, 0xFF63B8FF, 0xFFFFFFFF};
    public static final int DELAY = 10;
    public static final int BAR_GROWTH_STEP = 15;

    public AnswererBarChart(Context context) {
        this(context, null);
    }

    public AnswererBarChart(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AnswererBarChart(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        // region 两端文本描述 及 错误选项
        mXAxisLabelPaint = new Paint();
        mXAxisLabelPaint.setColor(ThemeDataUtil.getColorFromThemeConfigByAttrId(context, R.attr.base_theme_window_main_text_color));
        mXAxisLabelPaint.setAntiAlias(true);
        mXAxisLabelPaint.setTextSize(dip2px(context, 11));
        mXAxisLabelPaint.setTextAlign(Paint.Align.CENTER);
        // endregion

        // region 正确选项
        mXAxisSelectedLabelPaint = new Paint();
        mXAxisSelectedLabelPaint.setAntiAlias(true);
        mXAxisSelectedLabelPaint.setTextSize(dip2px(context, 11));
        mXAxisSelectedLabelPaint.setColor(ThemeDataUtil.getColorFromThemeConfigByAttrId(context, R.attr.base_theme_live_product_color));
        mXAxisSelectedLabelPaint.setTextAlign(Paint.Align.CENTER);
        // endregion

        // region 选择占比百分值 文本
        mYAxisValuePaint = new Paint();
        mYAxisValuePaint.setColor(ThemeDataUtil.getColorFromThemeConfigByAttrId(context, R.attr.base_theme_window_main_text_color));
        mYAxisValuePaint.setAntiAlias(true);
        mYAxisValuePaint.setTextSize(dip2px(context, 9));
        mYAxisValuePaint.setTextAlign(Paint.Align.CENTER);
        // endregion

        // region 值 柱
        mBarPaint = new Paint();
        mBarPaint.setColor(mColors[1]);
        mBarPaint.setAntiAlias(true);
        mBarWidth = dip2px(context, 10);
        // endregion

        // region 轴横线
        mXAxisPaint = new Paint();
        mXAxisPaint.setColor(ThemeDataUtil.getColorFromThemeConfigByAttrId(context, R.attr.base_theme_window_main_text_color));
        mXAxisPaint.setAntiAlias(true);
        mXAxisPaint.setStrokeWidth(2);
        // endregion

        mTextRect = new Rect();
        mValueRect = new Rect();
        mCountRect = new Rect();
        mRateRect = new Rect();
        mBarRectF = new RectF();
        mClipRectF = new RectF();

        mGap = dip2px(context, 4);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mBars.clear();
        if (mHorizontalAxis == null || mHorizontalAxis.length == 0) {
            return;
        }
        mXAxisLabelPaint.getTextBounds(mHorizontalAxis[0], 0, mHorizontalAxis[0].length(), mTextRect);
        mYAxisValuePaint.getTextBounds(mHorizontalAxis[0], 0, mHorizontalAxis[0].length(), mValueRect);
        mXAxisLabelPaint.getTextBounds(mCountString, 0, mCountString.length(), mCountRect);
        mXAxisLabelPaint.getTextBounds(mRateString, 0, mRateString.length(), mRateRect);
        int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - (mCountRect.width() + mRateRect.width() + 2 * mGap);
        int height = getMeasuredHeight() - getPaddingBottom() - getPaddingTop();
        mStep = width / mDataList.length;
        mRadius = mBarWidth / 2;
        int barLeft = getPaddingLeft() + mStep / 2 - mRadius + mCountRect.width() + mGap;
        int maxBarHeight = height - mTextRect.height() * 2 - mGap * 2;
        float heightRatio = maxBarHeight / mMax;
        for (float data : mDataList) {
            AnswererBarEntry bar = new AnswererBarEntry();
            bar.setValue(data);
            bar.setTransformedValue(bar.getValue() * heightRatio);
            bar.setLeft(barLeft);
            bar.setTop((int) (getPaddingTop() + maxBarHeight - bar.getTransformedValue() + mTextRect.height() + mGap));
            bar.setRight(bar.getLeft() + mBarWidth);
            bar.setBottom(getPaddingBottom() + maxBarHeight + mValueRect.height() + mGap);
            bar.setCurrentTop(bar.getBottom());
            mBars.add(bar);
            barLeft += mStep;
        }
    }

    private int getMaxDataTop(List<AnswererBarEntry> bars) {
        int maxTop = bars.get(0).getTop();
        for (AnswererBarEntry entry : bars) {
            if (maxTop > entry.getTop()) {
                maxTop = entry.getTop();
            }
        }
        return maxTop;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mBars == null || mBars.size() == 0) {
            return;
        }
        LPLogger.d("canStop:" + canStop);
        canStop = false;
        AnswererBarEntry startBar = mBars.get(0);
        int startX = startBar.getLeft() + mRadius;
        int startY = startBar.getBottom();
        AnswererBarEntry endBar = mBars.get(mBars.size() - 1);
        int endX = endBar.getRight() - mRadius;
        int endY = endBar.getBottom();
        canvas.drawLine(startX - mStep * 0.5f * mRatio, startY, endX + mStep * 0.5f * mRatio, endY, mXAxisPaint);
        Paint.FontMetrics fm = mXAxisLabelPaint.getFontMetrics();
        float textHeight = Math.abs(fm.ascent - fm.descent);
        float descLeftY = startY + textHeight / 2 - Math.abs(fm.descent);
        float descLeftX = startX - mGap - mCountRect.width() * 0.5f - mStep * 0.5f * mRatio;
        float descRightX = endX + mGap + mRateRect.width() * 0.5f + mStep * 0.5f * mRatio;
        canvas.drawText(mCountString, descLeftX, descLeftY, mXAxisLabelPaint);
        canvas.drawText(mRateString, descRightX, descLeftY, mXAxisLabelPaint);
        int length = mDataList.length;
        for (int i = 0; i < length; i++) {
            AnswererBarEntry bar = mBars.get(i);
            String axis = mHorizontalAxis[i];
            float textX = bar.getLeft() + mRadius;
            float textY = bar.getBottom() + mGap + mTextRect.height();
            if (mSelectedAxis != null && mSelectedAxis.size() != 0 && mSelectedAxis.contains(axis)) {
                canvas.drawText(axis, textX, textY, mXAxisSelectedLabelPaint);
            } else {
                canvas.drawText(axis, textX, textY, mXAxisLabelPaint);
            }
            bar.setCurrentTop(bar.getCurrentTop() - BAR_GROWTH_STEP);
            if (bar.getCurrentTop() <= bar.getTop()) {
                bar.setCurrentTop(bar.getTop());
                if (bar.getCurrentTop() == getMaxDataTop(mBars)) {
                    canStop = true;
                }
            }
            mBarRectF.set(bar.getLeft(), bar.getCurrentTop(), bar.getRight(), bar.getBottom() + mRadius);
            mClipRectF.set(bar.getLeft(), bar.getCurrentTop(), bar.getRight(), bar.getBottom());
            canvas.drawText(String.valueOf((int)bar.getValue()).concat("%"), textX, bar.getCurrentTop() - mGap, mYAxisValuePaint);
            LinearGradient linearGradient = new LinearGradient(bar.getLeft(), bar.getBottom(), bar.getRight(), bar.getTop(), mColors, null, Shader.TileMode.CLAMP);
            mBarPaint.setShader(linearGradient);
            canvas.save();
            canvas.clipRect(mClipRectF);
            canvas.drawRoundRect(mBarRectF, mRadius, mRadius, mBarPaint);
            canvas.restore();
        }
        if (!canStop) {
            postInvalidateDelayed(DELAY);
        }
    }

    /**
     * 横轴数据
     *
     * @param horizontalAxis
     */
    public void setHorizontalAxis(String[] horizontalAxis) {
        mHorizontalAxis = horizontalAxis;
    }
    public void setHorizontalAxis(List<String> horizontalAxis) {
        mHorizontalAxis = horizontalAxis.toArray(new String[horizontalAxis.size()]);
    }

    public void setMax(float max) {
        mMax = max;
    }

    /**
     * 数据
     *
     * @param dataList
     */
    public void setDataList(float[] dataList) {
        mDataList = dataList;
    }

    /**
     * 选择的横轴数据
     *
     * @param selectedAxis
     */
    public void setSelectedAxis(String[] selectedAxis) {
        mSelectedAxis = Arrays.asList(selectedAxis);
    }
    public void setSelectedAxis(List<String> selectedAxis) {
        mSelectedAxis = selectedAxis;
    }

    /**
     * 横轴左边label
     *
     * @param mCountString
     */
    public void setCountString(String mCountString) {
        this.mCountString = mCountString;
    }

    /**
     * 横轴右边的label
     *
     * @param rateString
     */
    public void setRateString(String rateString) {
        this.mRateString = rateString;
    }

    /**
     * x轴长度因子最大为1(影响左右label与横向布局的padding,1即占满整个横向布局)。
     *
     * @param ratio
     */
    public void setRatio(float ratio) {
        if (ratio > 1) {
            this.mRatio = 1;
        }
        this.mRatio = ratio;
    }

    private static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}
